// @ts-nocheck
import * as Util from './util.esm.js';
import CustomPrimitive from './custom-primitive.esm.js';
let randomIndexs = [];
import { calculateSpeedFragShader } from '../glsl/calculateSpeed.frag.js';
import { updatePositionFragShader } from '../glsl/updatePosition.frag.js';
import { postProcessingPositionFragShader } from '../glsl/postProcessingPosition.frag.js';

const randomizeParticlesWithData = (maxCount, data) => {
  const ldmaxPaticle = data.lat.array.length;
  maxCount > ldmaxPaticle ? (maxCount = ldmaxPaticle) : 0;
  randomIndexs = [];
  const array = new Float32Array(4 * maxCount);
  const length = maxCount > data['lat'].array.length ? data['lat'].array.length : maxCount;
  for (let i = 0; i < length; i++) {
    var tempIndex = parseInt(Math.random() * ldmaxPaticle, 10);
    randomIndexs.push(tempIndex);
    array[4 * i] = data['lon'].array[tempIndex]; // texel 的 R
    array[4 * i + 1] = data['lat'].array[tempIndex]; // texel 的 G
    array[4 * i + 2] = 100; // texel 的 B
    array[4 * i + 3] = 0; // texel 的 A
  }
  return array;
};

const randomizeParticlesSpeedWithData = (maxCount, data) => {
  const ldmaxPaticle = data.lat.array.length;
  maxCount > ldmaxPaticle ? (maxCount = ldmaxPaticle) : 0;
  const array = new Float32Array(4 * maxCount);
  const length = maxCount > data['lat'].array.length ? data['lat'].array.length : maxCount;
  for (let i = 0; i < length; i++) {
    array[4 * i] = data['u'].array[randomIndexs[i]]; // texel 的 R
    array[4 * i + 1] = data['v'].array[randomIndexs[i]]; // texel 的 G
    array[4 * i + 2] = 1; // texel 的 B
    array[4 * i + 3] = 1; // texel 的 A
  }
  return array;
};

export default class ParticlesComputing {
  constructor(context, data, userInput, viewerParameters) {
    this.context = context;
    this.data = data;
    this.createWindTextures(context, data);
    this.createParticlesTextures(context, userInput, viewerParameters);
    this.createComputingPrimitives(data, userInput, viewerParameters);
  }

  createWindTextures(context, data) {
    var windTextureOptions = {
      context: context,
      width: data.dimensions.lon,
      height: data.dimensions.lat * data.dimensions.lev,
      pixelFormat: Cesium.PixelFormat.LUMINANCE,
      pixelDatatype: Cesium.PixelDatatype.FLOAT,
      flipY: false,
      sampler: new Cesium.Sampler({
        // the values of texture will not be interpolated
        minificationFilter: Cesium.TextureMinificationFilter.NEAREST,
        magnificationFilter: Cesium.TextureMagnificationFilter.NEAREST
      })
    };

    this.windTextures = {
      u: Util.createTexture(windTextureOptions, data.u.array),
      v: Util.createTexture(windTextureOptions, data.v.array)
    };
  }

  createParticlesTextures(context, userInput, viewerParameters) {
    const particlesTextureOptions = {
      context: context,
      width: userInput.particlesTextureSize,
      height: userInput.particlesTextureSize,
      pixelFormat: Cesium.PixelFormat.RGBA,
      pixelDatatype: Cesium.PixelDatatype.FLOAT,
      flipY: false,
      sampler: new Cesium.Sampler({
        // the values of texture will not be interpolated
        minificationFilter: Cesium.TextureMinificationFilter.NEAREST,
        magnificationFilter: Cesium.TextureMagnificationFilter.NEAREST
      })
    };

    // 使用经纬度数值对，创造四维向量连续数组，即 [lon1, lat1, 100, 0, lon2, lat2, 100, 0, ...]
    const particlesArray = randomizeParticlesWithData(userInput.maxParticles, this.data);
    // 使用 uv 数值对，创造四维向量连续数组，即 [u1, v1, 1, 1, u2, v2, 1, 1, ...]
    const particlesSpeedArray = randomizeParticlesSpeedWithData(userInput.maxParticles, this.data);
    const zeroArray = new Float32Array(4 * userInput.maxParticles).fill(0);

    this.particlesTextures = {
      initParticlesPosition: Util.createTexture(particlesTextureOptions, particlesArray), // 初始粒子位置纹理
      previousParticlesPosition: Util.createTexture(particlesTextureOptions, particlesArray), // 前帧粒子位置纹理
      currentParticlesPosition: Util.createTexture(particlesTextureOptions, particlesArray), // 当前帧粒子位置纹理
      nextParticlesPosition: Util.createTexture(particlesTextureOptions, particlesArray), // 下一帧粒子位置纹理
      postProcessingPosition: Util.createTexture(particlesTextureOptions, particlesArray), // 后处理的位置纹理

      initparticlesSpeedUV: Util.createTexture(particlesTextureOptions, zeroArray), // 初速度纹理
      particlesSpeedUV: Util.createTexture(particlesTextureOptions, particlesSpeedArray), // 粒子UV速度向量场纹理
      particlesSpeed: Util.createTexture(particlesTextureOptions, zeroArray) // 粒子速度纹理
    };
  }

  destroyParticlesTextures() {
    Object.keys(this.particlesTextures).forEach((key) => {
      this.particlesTextures[key].destroy();
    });
  }

  createComputingPrimitives(data, userInput, viewerParameters) {
    const dimension = new Cesium.Cartesian3(
      data.dimensions.lon,
      data.dimensions.lat,
      data.dimensions.lev
    );
    const minimum = new Cesium.Cartesian3(data.lon.min, data.lat.min, data.lev.min);
    const maximum = new Cesium.Cartesian3(data.lon.max, data.lat.max, data.lev.max);
    const interval = new Cesium.Cartesian3(
      (maximum.x - minimum.x) / (dimension.x - 1),
      (maximum.y - minimum.y) / (dimension.y - 1),
      dimension.z > 1 ? (maximum.z - minimum.z) / (dimension.z - 1) : 1.0
    );
    const uSpeedRange = new Cesium.Cartesian2(data.u.min, data.u.max);
    const vSpeedRange = new Cesium.Cartesian2(data.v.min, data.v.max);

    const that = this;

    var n = 0;
    this.primitives = {
      calculateSpeed: new CustomPrimitive({
        commandType: 'Compute',
        uniformMap: {
          U: function () {
            return that.windTextures.u;
          },
          V: function () {
            return that.windTextures.v;
          },
          currentParticlesPosition: function () {
            /* if(n%30==0){
              that.destroyParticlesTextures();
              that.createParticlesTextures(that.context,userInput, viewerParameters);
              n=1;
            }
            n++; */
            return that.particlesTextures.currentParticlesPosition;
          },
          particlesSpeedUV: function () {
            return that.particlesTextures.particlesSpeedUV;
          },
          dimension: function () {
            return dimension;
          },
          minimum: function () {
            return minimum;
          },
          maximum: function () {
            return maximum;
          },
          interval: function () {
            return interval;
          },
          uSpeedRange: function () {
            return uSpeedRange;
          },
          vSpeedRange: function () {
            return vSpeedRange;
          },
          pixelSize: function () {
            return viewerParameters.pixelSize;
          },
          speedFactor: function () {
            return userInput.speedFactor;
          }
        },
        fragmentShaderSource: new Cesium.ShaderSource({
          sources: [calculateSpeedFragShader]
        }),
        outputTexture: this.particlesTextures.particlesSpeed,
        preExecute: function () {
          // swap textures before binding
          var temp;
          temp = that.particlesTextures.previousParticlesPosition;
          that.particlesTextures.previousParticlesPosition =
            that.particlesTextures.currentParticlesPosition;
          that.particlesTextures.currentParticlesPosition =
            that.particlesTextures.postProcessingPosition;
          that.particlesTextures.postProcessingPosition = temp;

          // keep the outputTexture up to date
          that.primitives.calculateSpeed.commandToExecute.outputTexture =
            that.particlesTextures.particlesSpeed;
        }
      }),

      updatePosition: new CustomPrimitive({
        commandType: 'Compute',
        uniformMap: {
          currentParticlesPosition: function () {
            return that.particlesTextures.currentParticlesPosition;
          },
          particlesSpeed: function () {
            return that.particlesTextures.particlesSpeed;
          }
        },
        fragmentShaderSource: new Cesium.ShaderSource({
          sources: [updatePositionFragShader]
        }),
        outputTexture: this.particlesTextures.nextParticlesPosition,
        preExecute: function () {
          // keep the outputTexture up to date
          that.primitives.updatePosition.commandToExecute.outputTexture =
            that.particlesTextures.nextParticlesPosition;
        }
      }),

      postProcessingPosition: new CustomPrimitive({
        commandType: 'Compute',
        uniformMap: {
          nextParticlesPosition: function () {
            return that.particlesTextures.nextParticlesPosition;
          },
          particlesSpeed: function () {
            return that.particlesTextures.particlesSpeed;
          },
          lonRange: function () {
            return viewerParameters.lonRange;
          },
          latRange: function () {
            return viewerParameters.latRange;
          },
          randomCoefficient: function () {
            var randomCoefficient = Math.random();
            return randomCoefficient;
          },
          dropRate: function () {
            return userInput.dropRate;
          },
          dropRateBump: function () {
            return userInput.dropRateBump;
          },
          initParticlesPosition: function () {
            return that.particlesTextures.initParticlesPosition;
          },
          pixwidth: function () {
            return userInput.particlesTextureSize;
          },
          pixheight: function () {
            return userInput.particlesTextureSize;
          }
        },
        fragmentShaderSource: new Cesium.ShaderSource({
          sources: [postProcessingPositionFragShader]
        }),
        outputTexture: this.particlesTextures.postProcessingPosition,
        preExecute: function () {
          // keep the outputTexture up to date
          that.primitives.postProcessingPosition.commandToExecute.outputTexture =
            that.particlesTextures.postProcessingPosition;
        }
      })
    };
  }
}
